package pipe

import (
	"gitee.com/injoyai/goutil/chans"
	"gitee.com/injoyai/goutil/conv"
	"gitee.com/injoyai/goutil/net/tcp/v2"
	"gitee.com/injoyai/goutil/oss/io"
	"gitee.com/injoyai/goutil/string/logs/v1"
	"log"
)

func NewClient(addr, sn string, num ...int) *Client {
	cli := &Client{
		sn:    sn,
		addr:  addr,
		queue: chans.NewEntity(conv.GetDefaultInt(20, num...)),
		Proxy: NewProxy().SetKey(sn),
	}
	cli.queue.SetHandler(cli.dealQueue)
	cli.Client = cli.newDial(addr, sn)
	cli.Proxy.SetConnectFunc(ConnectWithDefault(cli.Client))
	return cli
}

// Client 通道客户端
type Client struct {
	*tcp.Client               //通道客户端
	sn          string        //客户端标识
	addr        string        //通道服务端地址
	queue       *chans.Entity //执行队列
	Proxy       *Proxy        //代理客户端连接池
}

// Write 给服务端发数据
func (this *Client) Write(msg []byte) (int, error) {
	return this.Client.Write(NewInfoMsg(this.sn, msg).Bytes())
}

// SetRedirectFunc 自定义重定向函数
func (this *Client) SetRedirectFunc(i IRedirect) *Client {
	this.Proxy.SetRedirect(i)
	return this
}

// Redirect 重定向,*表示重定向全部,用默认重定向函数是生效
func (this *Client) Redirect(oldAddr, newAddr string) *Client {
	this.Proxy.Redirect(oldAddr, newAddr)
	return this
}

// Wait 一直等待
func (this *Client) Wait() {
	select {}
}

// dealQueue 队列,协程控制
func (this *Client) dealQueue(no, num int, data interface{}) {
	msg := data.(*io.Message)
	m, err := DecodeMsg(msg.Bytes())
	if err != nil {
		//不能确定是那个代理连接
		logs.Err("解析失败:", msg.String())
		return
	}
	if err := this.Proxy.Switch(m); err != nil {
		log.Printf("[错误][%s] %s", msg.Key(), err.Error())
		this.Client.Write(NewCloseMsg(m.Key, err.Error()).Bytes())
	}
}

// newClient 新建通道客户端
func (this *Client) newDial(addr, sn string) *tcp.Client {
	return tcp.Redial(addr, func(c *tcp.Client) {
		this.Proxy.CloseConnAll()
		c.SetPrintFunc(PrintWithPipe)
		c.SetWriteFunc(WriteWithBase64)
		c.SetReadFunc(ReadWithBase64)
		c.SetDealFunc(func(msg *io.Message) { this.queue.Do(msg) })
		c.SetPrintWithASCII()
		c.SetKey(sn)
		c.Write(NewRegisterMsg(sn, "").Bytes())
		c.SetKeepAlive(DefaultKeepAlive, NewRegisterMsg(sn, "").Bytes())
	})
}
